#ifndef LINEAGES_H_INCLUDED
#define LINEAGES_H_INCLUDED

#include <lineages.h>
#include <vector>
#include <string>
#include <iostream>
#include <map>

using namespace std;

class Lineages
{
    friend ostream& operator<<(ostream& os, const Lineages&);

public:
    Lineages(vector<int> terminalTypes,vector<string> terminalLineages);
    ~Lineages();
    double complexity();
    double robustness(int disturbType, int robustType);
    double robustnessGamma(int disturbType, int robustType, double shapeK, double mean);
    void coalescent(); // populate the internal nodes
    void setDeathRates(vector<double> deathRates); // parameter must be in the same order of internLineages;
    void divideTerminal(string termLineage,int childType1,int childType2); // TODO

    static const int sparableCellType = -9999;

    vector<double> depth2DivRate; // map depth to its division rate
    int internalTypeCnt;

    vector<int> internalTypes; // internal types, name them as 0,1,2,3,4..
    vector<string> allLineages; // internal lineages, used when tracing the lineage for complexity/robustness
    map<string,int> lineages2allIndex;
    map<int,vector<int> > internalTypes2allIndex;
    vector<string> internalDesc; // description of internal nodes, concatenation of the types of both node.
    map<int,vector<int> > allIndex2DescendantIndex;
    map<int,int> totalTermType2Count;
    vector<int> diffDepth;
    vector<int> prolifDepth;

//private:
    void getDepthStat();

    double linCompl; // complexity of this lineage
    double linRobust1; // robustness of this lineage
    double linRobust2;
    double linRobust3;
    double linRobustSE;
    double depthMean;
    double depthSD;
    double depthMax;

    vector<int> termTypes; // terminal types
    vector<string> termLineages; // terminal lineages
    // these "term-" variables should have synchronized subscript

    vector<double> deaRates; // death rates

    // delete cells
    double cellDeletionRate;
    double robustness1(int robustType);
    double robustness1_Detail(int robustType, vector<double> &allRobustness);
	double robustness1Gamma(int robustType,double shapeK, double mean);

    // delete rules (a certain fraction of rules, NOT number of rules)
    double ruleDeletionRate;
    double robustness2(int robustType);
    double robustness2Sample(int robustType);
    double robustness2Sample_Detail(int robustType,vector<double> &allRobustness);
	double robustness2SampleGamma(int robustType,double shapeK,double mean);

    // delete cells with changing rates along time
    vector<double> depthSpecificDeletionRate;
    double robustness3(int robustType);

    double disturbedSurvival(int robustType, map<int,int> termType2Count, map<int,int> termType2DeathCount); // types of fitness:
    // 1) fraction of each type of cells
    // 2) fraction of all cell
    // 3) weighted fraction of each type of cells

    map<int,double> types2Weight;

    double factln(int n);
    double binom(double p, int n, int k);
};
#endif // LINEAGES_H_INCLUDED
